package org.dromara.common.oss.factory

import io.github.oshai.kotlinlogging.KotlinLogging
import org.dromara.common.core.constant.CacheNames
import org.dromara.common.core.utils.StringUtils
import org.dromara.common.json.utils.JsonUtils.parseObject
import org.dromara.common.oss.constant.OssConstant
import org.dromara.common.oss.core.OssClient
import org.dromara.common.oss.exception.OssException
import org.dromara.common.oss.properties.OssProperties
import org.dromara.common.redis.utils.CacheUtils.get
import org.dromara.common.redis.utils.RedisUtils.getCacheObject
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.locks.ReentrantLock

/**
 * 文件上传Factory
 *
 * @author Lion Li
 * @updater LikeYouDo
 * @date 2025/1/27 23:31
 */
open class OssFactory {
    companion object {
        private val log = KotlinLogging.logger { }

        private val CLIENT_CACHE: MutableMap<String, OssClient> = ConcurrentHashMap()
        private val LOCK: ReentrantLock = ReentrantLock()

        /**
         * 获取默认实例
         */
        @JvmStatic
        fun instance(): OssClient? {
            // 获取redis 默认类型
            val configKey = getCacheObject<String>(OssConstant.DEFAULT_CONFIG_KEY)
            if (configKey.isNullOrEmpty()) {
                throw OssException("文件存储服务类型无法找到!")
            }
            return instance(configKey)
        }

        /**
         * 根据类型获取实例
         */
        @JvmStatic
        fun instance(configKey: String): OssClient? {
            val json = get<String>(CacheNames.SYS_OSS_CONFIG, configKey)
                ?: throw OssException("系统异常, '$configKey'配置信息不存在!")
            val properties = parseObject(json, OssProperties::class.java)
            // 使用租户标识避免多个租户相同key实例覆盖
            var key = configKey
            if (StringUtils.isNotBlank(properties.tenantId)) {
                key = properties.tenantId + ":" + configKey
            }
            var client = CLIENT_CACHE[key]
            // 客户端不存在或配置不相同则重新构建
            if (client == null || !client.checkPropertiesSame(properties)) {
                LOCK.lock()
                try {
                    client = CLIENT_CACHE[key]
                    if (client == null || !client.checkPropertiesSame(properties)) {
                        CLIENT_CACHE[key] = OssClient(configKey, properties)
                        log.info { "创建OSS实例 key => $configKey" }
                        return CLIENT_CACHE[key]
                    }
                } finally {
                    LOCK.unlock()
                }
            }
            return client
        }
    }
}
